package com.sxt.demo.djiapplication.activity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.TextureView
import android.view.View
import com.amap.api.maps2d.CameraUpdateFactory
import com.amap.api.maps2d.model.*
import com.sxt.demo.djiapplication.DjiDemoApplication
import com.sxt.demo.djiapplication.R
import com.sxt.demo.djiapplication.common.CommonConstants
import com.sxt.demo.djiapplication.dao.FlightDataService
import com.sxt.demo.djiapplication.dao.WayPointRecordItemService
import com.sxt.demo.djiapplication.databinding.ActivityMainBinding
import com.sxt.demo.djiapplication.databinding.RecordSelectorLayoutBinding
import com.sxt.demo.djiapplication.dji.CaptureOperator
import com.sxt.demo.djiapplication.dji.DJIDemoContext
import com.sxt.demo.djiapplication.dji.WayPoint
import com.sxt.demo.djiapplication.dji.WayPointMissionOperator
import com.sxt.demo.djiapplication.entity.flightdata.param.FlightDataAddParam
import com.sxt.demo.djiapplication.map.IMap
import com.sxt.demo.djiapplication.map.MarkerSets
import com.sxt.demo.djiapplication.map.OnMapClickListener
import com.sxt.demo.djiapplication.map.OnMarkerClickListener
import com.sxt.demo.djiapplication.map.gaodemap.GaoDeMap
import com.sxt.demo.djiapplication.utils.*
import com.sxt.demo.djiapplication.view.FlightDataFloatView
import com.xuexiang.xui.widget.popupwindow.popup.XUIPopup
import dji.common.error.DJIError
import dji.common.flightcontroller.FlightControllerState
import dji.common.useraccount.UserAccountState
import dji.common.util.CommonCallbacks.CompletionCallbackWith
import dji.sdk.base.BaseProduct
import dji.sdk.flightcontroller.FlightController
import dji.sdk.products.Aircraft
import dji.sdk.useraccount.UserAccountManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import com.sxt.demo.djiapplication.utils.ToastUtils

import com.xuexiang.xui.widget.dialog.bottomsheet.BottomSheet
import java.lang.RuntimeException


class MainActivity : BaseActivity(), View.OnClickListener, View.OnLongClickListener {

    private var mProduct: BaseProduct? = null

    private var videoCapture: CaptureOperator? = null

    /**
     * 地图上标记飞机位置的图标
     */
    private var droneMarker: Marker? = null

    /**
     * 无人机经度
     */
    private var droneLocationLng: Double = 0.0

    /**
     * 无人机纬度
     */
    private var droneLocationLat: Double = 0.0

    /**
     * 飞行控制器
     */
    private var mFlightController: FlightController? = null

    private val binding: ActivityMainBinding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    private val flightDataFloatView: FlightDataFloatView by lazy {
        FlightDataFloatView(this)
    }

    /**
     * 速度相关view
     */
    private val velocityView: FlightDataFloatView.VelocityViewHolder
            by lazy { flightDataFloatView.velocityViewHolder }

    /**
     * 电池相关view
     */
    private val electricView: FlightDataFloatView.ElectricViewHolder
            by lazy { flightDataFloatView.electricViewHolder }

    /**
     * 地图操作对象
     */
    private lateinit var iMap: IMap<Marker>


    /**
     * 是否可以添加位点
     */
    private var canAddWayPoint = false

    /**
     * 是否可以移除位点
     */
    private var canRemoveWayPoint = false

    /**
     * 画面预览
     */
    private var isPreviewing = false

    /**
     * 当前飞机电压
     */
    private var currentVoltage = 0

    /**
     * 当前飞机电流
     */
    private var currentCurrent = 0

    /**
     * 是否开始记录飞行数据
     */
    private var isRecordingFlightData = false

    /**
     * 视频预览view
     */
    private val videoCaptureView: TextureView by lazy { binding.videoPreviewerSurface }


    /**
     * 位点任务operator
     */
    private val wayPointMissionOperator: WayPointMissionOperator by lazy {
        WayPointMissionOperator(this)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
    }

    override fun exitActivity() {
        finish()
    }

    override fun init(bundle: Bundle?) {
        initMapView(bundle)
        registerBroadcastReceiver()
        onProductConnectionChange()
        initLocationButton()
        initControlView()
    }

    private fun registerBroadcastReceiver() {
        registerDJIReceiver()
        registerLoadRecordReceiver()
    }

    private fun initVideoCapture(product: BaseProduct) {
        videoCapture = CaptureOperator(this, product, videoCaptureView)
        videoCapture?.initCapture()
    }

    private fun destroyVideoCapture() {
        videoCapture?.destroyCapture()
    }

    private fun initControlView() {
        binding.btGlobalConfig.setOnClickListener(this)
        binding.btFlightDataFloatView.setOnClickListener(this)
        binding.btAddWayPoint.setOnClickListener(this)
        binding.btUploadMission.setOnClickListener(this)
        binding.btStartMission.setOnClickListener(this)
        binding.btStopMission.setOnClickListener(this)
        binding.btStopMission.setOnClickListener(this)
        binding.btnRecord.setOnClickListener(this)
        binding.btCapturePreview.setOnClickListener(this)
        binding.exitPreview.setOnClickListener(this)
        binding.btnRecord.setOnLongClickListener(this)
        binding.btAddWayPoint.setOnLongClickListener(this)
    }

    /**
     * 显示记录按钮选项Popup悬浮窗
     */
    private fun showRecordSelectorPopup(it: View?) {
        val recordSelector = RecordSelectorLayoutBinding.inflate(layoutInflater)
        recordSelector.tvExport.setOnClickListener {
            flightDataService.getFlightDataExcelFile {
                LogUtil.e(it?.absolutePath)
                it?.let {
                    ShareUtil.allShare(
                        ShareUtil.ShareIntentBuilder(this)
                            .subject("分享到")
                            .title("分享")
                            .content(it)
                    )
                }
            }
        }
        recordSelector.tvClear.setOnClickListener {
            flightDataService.removeAllData()
        }
        val mNormalPopup = XUIPopup(this)
        mNormalPopup.setContentView(recordSelector.root)
        mNormalPopup.setAnimStyle(XUIPopup.ANIM_GROW_FROM_CENTER)
        mNormalPopup.setPreferredDirection(XUIPopup.DIRECTION_TOP)
        mNormalPopup.show(it)
    }

    private fun initLocationButton() {
        binding.btnLocation.setOnClickListener {
            locateDrone()
        }
    }

    override fun onResume() {
        super.onResume()
        mProduct?.let { videoCapture?.initCapture() }
    }

    override fun onPause() {
        super.onPause()
        destroyVideoCapture()
    }

    override fun onDestroy() {
        super.onDestroy()
        flightDataFloatView.dismiss()
        unregisterReceiver(flightStatusBroadcastReceiver)
        wayPointMissionOperator.destroy()
        destroyVideoCapture()
    }

    private val flightStatusBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            onProductConnectionChange()
        }
    }

    private val loadRecordBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val id = intent.extras?.getLong("id")
            val service = DjiDemoApplication.getSingleObj(WayPointRecordItemService::class.java)
            val items = service.dao._queryWayPointRecord_WayPointRecordItems(id)
            val map = items.associateBy({
                iMap.addMarker(
                    MarkerSets(
                        MarkerOptions().position(
                            MCoordinateConverter.gps2GaoDeCoordinate(
                                LatLng(
                                    it.latitude,
                                    it.longitude
                                )
                            )
                        )
                            .icon(
                                BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE)
                            )
                    )
                )
            }, {
                WayPoint(it.latitude, it.longitude, it.needTakePic, it.altitude, it.speed, it.order)
            })

            wayPointMissionOperator.removeAllWayPoints()
            wayPointMissionOperator.addWayPointMap(map)

            ToastUtils.show(this@MainActivity, "加载成功")
        }

    }

    /**
     * 注册DJI事件Receiver
     * 监听飞行器连接的改变
     */
    private fun registerDJIReceiver() {
        registerReceiver(
            flightStatusBroadcastReceiver,
            IntentFilter(DJIDemoContext.FLAG_CONNECTION_CHANGE)
        )
    }

    /**
     * 注册位点记录加载事件Receiver
     * 用于位点的加载
     */
    private fun registerLoadRecordReceiver() {
        registerReceiver(
            loadRecordBroadcastReceiver,
            IntentFilter(CommonConstants.LOAD_WAYPOINT_BROADCAST)
        )
    }

    private fun onProductConnectionChange() {
        initFlightController()
        loginAccount()
    }

    private fun initFlightController() {
        val product = DJIDemoContext.getProductInstance()
        mProduct = product
        if (product != null && product.isConnected) {
            //当飞机连接时获取飞行控制器
            if (product is Aircraft) {
                mFlightController = product.flightController
            }
            // 设置当无人机状态发生改变后的回调
            mFlightController?.setStateCallback {
                // 更新无人机位置
                updateDroneLocation(it)

                // 更新无人机当前的三维速度等数据的显示
                updateFlightDataShow(it)

                // 记录飞行时的检测数据
                recordFlightData(it)
            }
            // 初始定位无人机
            locateDrone()
            // 设置无人机电池状态发生变化时的回调
            product.battery?.setStateCallback {
                runOnUiThread {
                    try {
                        electricView.voltage.text = getString(R.string.voltage, it.voltage)
                        electricView.current.text = getString(R.string.current, it.current)
                    } catch (e: Exception) {
                        ToastUtils.show(e.message)
                    }
                }
                // 记录飞行时的电压电流数据
                currentVoltage = it.voltage
                currentCurrent = it.current
            }

            // 开启无人机自动避障
            setAvoidanceEnabled()

            // 初始化相机捕捉
            initVideoCapture(product)
        }
    }

    /**
     * 开启无人机自动避障
     */
    private fun setAvoidanceEnabled() {
        mFlightController?.flightAssistant?.setActiveObstacleAvoidanceEnabled(true) {
            ToastUtils.show("避障操作开启")
        }
        mFlightController?.flightAssistant?.setCollisionAvoidanceEnabled(true) {
            ToastUtils.show("主动避障操作开启")
        }
    }

    /**
     * 更新无人机当前的三维速度等数据的显示
     */
    private fun updateFlightDataShow(flightControllerState: FlightControllerState) {
        runOnUiThread {
            try {
                velocityView.velocityX.text =
                    getString(R.string.velocity_x, flightControllerState.velocityX)
                velocityView.velocityY.text =
                    getString(R.string.velocity_y, flightControllerState.velocityY)
                velocityView.velocityZ.text =
                    getString(R.string.velocity_z, flightControllerState.velocityZ)
            } catch (e: Exception) {
                ToastUtils.show(e.message)
            }
        }
    }

    /**
     * 飞行数据保存Service
     */
    private val flightDataService = FlightDataService(this)

    /**
     * 记录飞行时的检测数据
     * 记录过程中穿插着记录按钮颜色的变化
     */
    private fun recordFlightData(flightControllerState: FlightControllerState) {
        if (isRecordingFlightData) {
            binding.btnRecord.setBackgroundResource(R.drawable.record_ring_red)
        } else {
            binding.btnRecord.setBackgroundResource(R.drawable.record_ring_gray)
            return
        }
        // 记录飞行时的检测数据
        CoroutineScope(Dispatchers.IO + Job()).launch {
            val aircraftLocation = flightControllerState.aircraftLocation
            flightDataService.addFlightData(
                FlightDataAddParam(
                    flightControllerState.velocityX,
                    flightControllerState.velocityY,
                    flightControllerState.velocityZ,
                    currentVoltage,
                    currentCurrent,
                    aircraftLocation.latitude,
                    aircraftLocation.longitude,
                    aircraftLocation.altitude,
                    mFlightController?.compass?.heading ?: 0.0f
                )
            )
        }
        binding.btnRecord.setBackgroundResource(R.drawable.record_ring_green)
    }

    /**
     * 无人机定位
     */
    private fun locateDrone() {
        updateDroneLocation(mFlightController?.state)
        cameraUpdate()
    }

    private fun updateDroneLocation(flightControllerState: FlightControllerState?) {
        flightControllerState?.let {
            //纬度
            droneLocationLat = it.aircraftLocation.latitude
            //经度
            droneLocationLng = it.aircraftLocation.longitude

            doUpdateDroneLocation()
        } ?: run {
            ToastUtils.show("定位失败, 可能没有连接无人机？？？")
        }
    }

    // 根据MCU的状态更新无人机位置
    private fun doUpdateDroneLocation() {
        var pos: LatLng? = LatLng(droneLocationLat, droneLocationLng)
        pos = MCoordinateConverter.gps2GaoDeCoordinate(pos)
        //创建 MarkerOptions 对象
        val markerOptions = MarkerOptions()
        markerOptions.position(pos)
        markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.aircraft))
        runOnUiThread {
            droneMarker?.remove()
            if (MCoordinateConverter.checkGpsCoordination(droneLocationLat, droneLocationLng)) {
                droneMarker = iMap.addMarker(MarkerSets(markerOptions))
            }
        }
    }

    private fun loginAccount() {
        UserAccountManager.getInstance().logIntoDJIUserAccount(this,
            object : CompletionCallbackWith<UserAccountState?> {
                override fun onSuccess(userAccountState: UserAccountState?) {
                    val rs = "Login Success"
                    LogUtil.i(rs)
                    ToastUtils.show(rs)
                    cameraUpdate()
                }

                override fun onFailure(error: DJIError) {
                    val rs = "Login Failed: ${error.description}"
                    LogUtil.e(rs)
                    ToastUtils.show(this@MainActivity, rs)
                }
            })
    }

    /**
     * 初始化地图
     */
    private fun initMapView(bundle: Bundle?) {
        iMap = GaoDeMap(this, bundle, binding.map)
        // 设置地图语言
        iMap.setMapLanguage(IMap.EN)
        setOnMapClickListener()
        //初始化坐标为深圳区域
        val shenZhen = LatLng(22.5362, 113.9454)
        //加一个Marker（标记）到地图上。
        //MarkerOptions 定义marker 图标的锚点
//        iMap.addMarker(
//            MarkerSets(
//                MarkerOptions().position(MCoordinateConverter.gps2GaoDeCoordinate(shenZhen))
//                    .title("Marker in Shenzhen")
//            )
//        )
        //按照传入的CameraUpdate 参数移动可视区域
        //这个方法为瞬间移动，没有移动过程，如果在调用此方法后在回调方法onCameraChangeFinish()中调用getCameraPosition()将返回移动后位置。
        iMap.moveCamera { CameraUpdateFactory.newLatLng(shenZhen) }
        // 当地图的标记点点击事件
        setOnMarkerClickListener()
    }

    private fun setOnMarkerClickListener() {
        iMap.setOnMarkerClickListener(object : OnMarkerClickListener() {
            override fun onMarkerClick(marker: Marker): Boolean {
                if (canRemoveWayPoint) {
                    markerSelectSheet(marker)
                }
                return true
            }
        })
    }

    private fun deleteWayPoint(marker: Marker) {
        wayPointMissionOperator.removeWayPoint(marker)
        marker.remove()
    }

    private fun markerSelectSheet(marker: Marker) {
        BottomSheet.BottomListSheetBuilder(this@MainActivity)
            .setTitle(
                getString(
                    R.string.modify_marker_sheet_title,
                    wayPointMissionOperator.getWayPointIndex(marker)
                )
            )
            .addItem(getString(R.string.modify), "M")
            .addItem(getString(R.string.delete), "D")
            .setOnSheetItemClickListener { dialog, _, _, tag ->
                dialog.dismiss()
                when (tag) {
                    "M" -> wayPointMissionOperator.modifyWayPoint(marker)
                    "D" -> deleteWayPoint(marker)
                }
            }
            .build()
            .show()
    }

    private fun setOnMapClickListener() {
        iMap.setOnMapClickListener(object : OnMapClickListener() {
            override fun onMapClick(latLng: LatLng) {
                if (canAddWayPoint) {
                    val markWayPoint = markWayPoint(latLng)
                    wayPointMissionOperator.addWayPoint(markWayPoint)
                }
            }
        })
    }

    /**
     * 在地图上添加一个位点
     */
    private fun markWayPoint(point: LatLng): Marker {
        val markerOptions = MarkerOptions()
        markerOptions.position(point)
        markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
        return iMap.addMarker(MarkerSets(markerOptions))
    }

    private fun cameraUpdate() {
        iMap.moveCamera {
            var pos: LatLng? = LatLng(droneLocationLat, droneLocationLng)
            pos = MCoordinateConverter.gps2GaoDeCoordinate(pos)
            val zoomlevel = 18.0.toFloat()
            CameraUpdateFactory.newLatLngZoom(pos, zoomlevel)
        }
    }

    override fun onClick(v: View?) {
        when (v) {
            binding.btGlobalConfig -> {
                wayPointMissionOperator.showGlobalConfig()
            }
            binding.btFlightDataFloatView -> flightDataFloatView.show()
            binding.btAddWayPoint -> {
                if (!canAddWayPoint) {
                    startWayPointAdd()
                } else {
                    endWayPointAdd()
                }
            }
            binding.btUploadMission -> {
                if (canAddWayPoint) {
                    ToastUtils.show(this, "请先退出位点添加再进行任务上传")
                    return
                }
                wayPointMissionOperator.uploadWayPointMission()
            }
            binding.btStartMission -> wayPointMissionOperator.startWayPointMission()
            binding.btStopMission -> wayPointMissionOperator.stopWayPointMission()
            binding.btnRecord -> {
                if (isRecordingFlightData) {
                    isRecordingFlightData = false
                    switchRecordBtnStyle(isRecordingFlightData)
                } else {
                    isRecordingFlightData = true
                    switchRecordBtnStyle(isRecordingFlightData)
                }
            }
            binding.btCapturePreview -> {
                if (!isPreviewing) {
                    binding.rlCapturePreview.visibility = View.VISIBLE
                } else {
                    binding.rlCapturePreview.visibility = View.INVISIBLE
                }
                isPreviewing = !isPreviewing
            }
            binding.exitPreview -> {
                binding.rlCapturePreview.visibility = View.INVISIBLE
                if (isPreviewing) {
                    isPreviewing = false
                }
//                throw RuntimeException("123111")
            }
        }
    }

    override fun onLongClick(v: View?): Boolean {
        when (v) {
            binding.btnRecord -> {
                if (!isRecordingFlightData) {
                    // 显示记录按钮选项Popup悬浮窗
                    showRecordSelectorPopup(v)
                } else {
                    ToastUtils.show(this, "请先停止记录再进行数据导出")
                }
                return true
            }
            binding.btAddWayPoint -> {
                if (!canAddWayPoint) {
                    startActivity(Intent(this, WayPointLoadActivity::class.java))

                } else {
                    ToastUtils.show(this, "请先退出位点添加再进行操作")
                }
                return true
            }
            else -> {
                return false
            }
        }
    }

    /**
     * 根据是否选择记录飞行数据
     * 切换飞行数据记录按钮的风格
     */
    private fun switchRecordBtnStyle(recordingFlightData: Boolean) {
        if (recordingFlightData) {
            binding.btnRecord.setBackgroundResource(R.drawable.record_ring_red)
        } else {
            binding.btnRecord.setBackgroundResource(R.drawable.record_ring_gray)
        }
    }

    /**
     * 开始位点添加
     */
    private fun startWayPointAdd() {
        binding.btAddWayPoint.text = getString(R.string.exit_add_point)
        canAddWayPoint = true
        canRemoveWayPoint = true
        binding.tvTip.text = getString(R.string.add_way_point_tip)
        binding.tvTip.visibility = View.VISIBLE
    }

    /**
     * 结束位点添加
     */
    private fun endWayPointAdd() {
        binding.btAddWayPoint.text = getString(R.string.add_way_point)
        canAddWayPoint = false
        canRemoveWayPoint = false
        binding.tvTip.visibility = View.INVISIBLE
    }

}

